# -*- coding: utf-8 -*-
# File : patch_deploy.py
# Author: taoyahui
# Date : 2021/6/19
from utils.ansible_util import *
from utils.path_util import *
from utils import mysql_util
from utils.mongo_util import *
import json
import datetime
import time
from results import *
import requests
from urllib3 import HTTPConnectionPool
pool = HTTPConnectionPool('http://localhost:5002', maxsize=100)


# 通过执行补丁组和资产组，升级补丁
# 参数:
# patch_group_id: 补丁组ID
# inventory_group_id: 资产组ID
def execute_task(strategy_id, patch_group_id, inventory_group_id, strategy_name, timestamp, is_test=None):
    group_id_list = find_relate_inventory_group(inventory_group_id)
    group_id_list = [str(x) for x in group_id_list]
    inventory_group_id_list_str = ",".join(group_id_list)
    # 找到资产组所有的资产
    find_inventory_sql = f"select ip, username, os, password from inventory " \
                         f"where group_id in ({inventory_group_id_list_str}) and username is not null and os is not null"

    # 如果有is_test表示需要根据is_test找对应条件的机器
    if is_test is not None:
        find_inventory_sql = f"select ip, username, os, password from inventory " \
                             f"where group_id in ({inventory_group_id_list_str}) and username is not null and os is not null and is_test = {is_test}"
    inventory_res_list = mysql_util.exec_sql_new(find_inventory_sql)


    # 列出补丁组对应的补丁信息
    find_patch_id_sql = f"""select a.patch_id, b.cve_id, b.cve_affect_packages from patch_group_rel as a
                            left join patch as b on a.patch_id = b.id
                            where a.patch_group_id = {patch_group_id}"""
    patch_res_list = mysql_util.exec_sql_new(find_patch_id_sql)

    # 生成hosts对象
    centos_list = []
    for inventory in inventory_res_list:
        if 'CentOS' in inventory[2]:
            centos_list.append(inventory)
    hosts = construct_hosts(centos_list)

    pkgs = []
    # 生成pkgs列表
    for patch_res in patch_res_list:
        packages = json.loads(patch_res[2])
        names = [package['name'] for package in packages]
        print(names)
        pkgs.extend(names)
    pkgs = list(set(pkgs))
    install_results = pkgs_install_playbook(hosts, pkgs)
    patch_deploy_log(strategy_id=strategy_id, strategy_name= strategy_name, timestamp=timestamp, results=install_results)
    return success_result


# 使用mongodb 记录补丁部署的日志
def patch_deploy_log(strategy_id, strategy_name, timestamp, results):
    res = {
        'strategy_id': strategy_id,
        'strategy_name': strategy_name,
        'timestamp': timestamp,
        'result': results
    }
    return insert_one_document('patch_distribute', 'strategy_log', res)


# 将资产列表整合组成hosts格式的数据
def construct_hosts(inventory_list):
    hosts = []
    for inventory in inventory_list:
        item = {'ip': inventory[0], 'username': inventory[1], 'password': inventory[3]}
        hosts.append(item)
    construct_hosts = {'test':{'hosts': hosts}}
    return construct_hosts


# TODO:对hosts是否用yum安装，和pkgs是否存在进行判断
# Covered : Gaoliang
# 根据包内容逐个在IP中安装
# 参数：hosts 要更新的组及组中对应的机器ip和username
#       pkgs：group中及主机待安装的软件包
# 返回值：全部安装成功返回0，
#         失败返回错误日志,如：
#           {
#               'vsftp': {
#                   'counts_success': 0,
#                   'counts_fail': 2,
#                   'counts_unreachable': 1,
#                    'failed': {
#                       '192.168.50.242': "Failed No package matching 'vsftp' found available, installed or updated",
# #                     '192.168.50.156': "Failed No package matching 'vsftp' found available, installed or updated",
#                   }
#                   'unreachable': {
#                       '192.168.50.243': 'Unreachable Failed to connect to the host via ssh: ssh: connect to host 192.168.50.243 port 22: No route to host'
#                   }
#               },
#               'openssl': {
#                   'counts_success': 2,
#                   'counts_fail': 0,
#                   'counts_unreachable': 1,
#                   'unreachable': {
#                       '192.168.50.243': 'Unreachable Failed to connect to the host via ssh: ssh: connect to host 192.168.50.243 port 22: No route to host'
#                   }
#               }
#           }
def pkgs_install_playbook(hosts, pkgs):
    ret = 0
    counts = 0
    results = []
    for pkg in pkgs:
        exucute_res = install_single(hosts, pkg)
        # res = {'name':pkg, 'result':exucute_res}
        results.append(exucute_res)
    return results


# 安装脚本的内容，输入参数格式如pkgs_install_ad_hoc
def install_single(hosts, pkg):
    # ret = 0
    # counts = 0
    # results = {}
    # mi = MyInventory()
    # mi._dynamic_inventory(hosts)
    # ansible = MyAnsiable(inventory=mi._inventory, connection='smart')
    # # for group, host in hosts.items():
    # #     ansible.run(hosts=group, module='yum', remote_user='root', args='name=%s state=latest' % (pkg))
    #
    # extra_var = {
    #     'host': 'test',
    #     'username': 'root',
    #     'module_name': [pkg]
    # }
    # abs_path = get_root_dir()
    # ansible.playbook(playbooks=[abs_path + '/playbook/patch_deploy.yaml'], var=extra_var)
    #
    # stdresult = ansible.get_result()
    # print(stdresult)
    # result = result_prase(stdresult)
    result = requests.post("http://localhost:5002/patch_deploy", json= {"hosts": hosts, "pkg":pkg})
    return result.json()


# 结果转换
def result_prase(result):
    fail_msg = {}
    success = result.get('success')
    failed = result.get('failed')
    unreachable = result.get('unreachable')
    counts_success = len(success)
    counts_fail = len(failed)
    counts_unreachable = len(unreachable)

    fail_msg['counts_success'] = counts_success
    fail_msg['counts_fail'] = counts_fail
    fail_msg['counts_unreachable'] = counts_unreachable
    fail_msg['failed'] = {}
    fail_msg['unreachable'] = {}

    if counts_fail != 0:
        for ip, fm in failed.items():
            msg = fm.get('msg')
            fail_msg['failed'][ip] = 'Failed ' + msg

    if counts_unreachable != 0:
        for ip, fm in unreachable.items():
            msg = fm.get('msg')
            fail_msg['unreachable'][ip] = 'Unreachable ' + msg

    return fail_msg


def find_relate_inventory_group(group_id):
    """
    寻找所有与输入资产组相关的id
    :param group_id:
    :return:
    """
    all_inventory_group_query_sql = f"select * from department_group"
    res_list = mysql_util.exec_sql_new(all_inventory_group_query_sql)
    group_pid_dict = {}
    for res in res_list:
        if res[2] not in group_pid_dict:
            group_pid_dict[res[2]] = [res[0]]
        else:
            group_pid_dict[res[2]].append(res[0])
    target_group_list = [group_id]
    target_group_list = fact_iter(group_pid_dict, group_id,target_group_list)
    return target_group_list
    # print(target_group_list)


def fact_iter(group_pid_dict, group_id,target_group_list):
    """
    递归寻找
    :param group_pid_dict:
    :param group_id:
    :param target_group_list:
    :return:
    """
    if group_id not in group_pid_dict:
        return target_group_list
    else:
        target_group_list = target_group_list + group_pid_dict[group_id]
        for s_group_id in group_pid_dict[group_id]:
            return fact_iter(group_pid_dict, s_group_id, target_group_list)





# 远程部署(暂时没用)
def deploy():
    hosts = {'t_g': {'hosts': [{'ip': "192.168.50.156", 'username': "root", 'password': "123456", 'port': 22},{'ip': "192.168.50.251", 'username': "root", 'password': "123456", 'port': 22}]}}
    mi = MyInventory()
    mi._dynamic_inventory(hosts)
    ansible = MyAnsiable(inventory=mi._inventory, connection='smart')
    extra_var = {
        'host': 't_g',
        'username': 'root',
        'module_name': ['openssl']
    }
    abs_path = get_root_dir()
    ansible.playbook(playbooks=[abs_path + '/playbook/patch_deploy.yaml'], var=extra_var)
    result = ansible.get_result()
    print(result)


def check():
    pass


if __name__ == '__main__':
    pass
    # hosts = {'test': {'hosts': [{'ip': '192.168.50.156', 'username': 'root' ,'password': "123456", 'port': 22},{'ip': '192.168.50.251', 'username': 'root', 'password': "123456", 'port': 22}]}}
    # pkgs = ['vsftpd', 'openssh', 'openssl']
    # import requests
    # for pkg in pkgs:
    #     r = requests.post("http://localhost:5002/patch_deploy", json= {"hosts": hosts, "pkg":pkg})
    #     print(r.json)
    # find_relate_inventory_group(1)
    # pkgs = ['openssl-lib']
    # from application_factory import scheduler
    # scheduler.add_job(func=pkgs_install_playbook,id="123123", kwargs={'hosts':hosts, 'pkgs':pkgs})
    # time.sleep(100)
    # deploy()
